//RealNumber.java
//Timothy Grant
//CS1410
//Calculator 1410
//Final Version

package numbers;

import java.util.Arrays;
import java.util.List;
//import java.util.ArrayList;

public class RealNumber implements Number {
    //instance fields

    private double number;
    private static String[] validOps = {"+", "-", "*", "/", "%"};
    private static String[] hiOps = {"*", "/", "%"};

    //begin set constructors
    public RealNumber(double n) {
        number = n;
    }

    public RealNumber(String s) {
        number = Double.parseDouble(s);
    }//end set constructors

    //add()
    public RealNumber add(RealNumber rightOpand) {
        return new RealNumber(this.number + rightOpand.number);
    }//end add method

    //subract()
    public RealNumber subtract(RealNumber rightOpand) {
        return new RealNumber(this.number - rightOpand.number);
    }//end subtract method

    //multiply()
    public RealNumber multiply(RealNumber rightOpand) {
        return new RealNumber(this.number * rightOpand.number);
    }//end multiply method

    //divide()
    public RealNumber divide(RealNumber rightOpand) {
        if (rightOpand.number == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        return new RealNumber(this.number / rightOpand.number);
    }//end divide method

    //equals()
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof RealNumber) {
            RealNumber temp = (RealNumber) obj;
            return this.number == temp.number;
        }
        return false;
    }//end equals method

    //toString()
    @Override
    public String toString() {
        return "" + this.number;
    }//end toString method

    //begin isValidOperator()
    public boolean isValidOperator(String s) {
        for (String x : validOps) {
            if (s.equals(x)) {
                return true;
            }
        }
        return false;
    }//end isValidOperator()

    //begin opand2Str()
    public String opand2Str(String e, int i) {
        int strIndex = i;
        char nextCh;
        boolean dPoint = false;
        String retStr = ("");

        try {
            nextCh = e.charAt(strIndex);
            if (nextCh == '-' || nextCh == '+') {
                retStr += nextCh;
                ++strIndex;
            }
            nextCh = e.charAt(strIndex);
        } catch (IndexOutOfBoundsException ex) {
            throw new ArithmeticException("Invalid Real Number");
        }

        try {
            if (nextCh == '.') {
                retStr += nextCh;
                ++strIndex;
                dPoint = true;
            }
            nextCh = e.charAt(strIndex);
        } catch (IndexOutOfBoundsException ex) {
            throw new ArithmeticException("Invalid Real Number" + ex.getMessage());
        }

        if (!Character.isDigit(nextCh)) {
            throw new ArithmeticException("Invalid Real Number");
        }

        do {
            if (nextCh == '.' && dPoint) {
                throw new ArithmeticException("Invalid Real Number");
            }
            retStr += nextCh;
            ++strIndex;

            try {
                nextCh = e.charAt(strIndex);
            } catch (IndexOutOfBoundsException ex) {
                return retStr;
            }
        } while (Character.isDigit(nextCh) || nextCh == '.');

        if (nextCh == 'e' || nextCh == 'E') {
            retStr += nextCh;
            ++strIndex;
            try {
                retStr += new IntegerNumber(0).opand2Str(e, strIndex);
            } catch (IndexOutOfBoundsException ex) {
                throw new ArithmeticException("Invalid Real Number" + ex.getMessage());
            }
        }

        return retStr;

    }//end opand2Str()

    //begin op2Str()
    public String op2Str(String e, int i) {
        int strIndex = i;
        char nextCh;
        String retStr = ("");

        try {
            nextCh = e.charAt(strIndex);
        } catch (IndexOutOfBoundsException ex) {
            throw new ArithmeticException("Invalid operation" + ex.getMessage());
        }

        if (isValidOperator(Character.toString(nextCh))) {
            retStr += nextCh;
            return retStr;
        } else if (!isValidOperator(Character.toString(nextCh))) {
            throw new ArithmeticException("Invalid operation");
        }

        return retStr;
    }//end op2Str()

    //begin str2Number()
    public Number str2Number(String s) {
        String numStr = "";
        try {
            numStr += new RealNumber(0).opand2Str(s, 0);
        } catch (ArithmeticException ex) {
            throw new ArithmeticException(s + " is an invalid integer number");
        }
        return new RealNumber(numStr);
    }//end str2Number()

    //begin doOp()
    public Number doOp(Number n1, Number n2, String op) {
        RealNumber result = new RealNumber(0);
        RealNumber num1;
        RealNumber num2;
        //System.out.printf("n1= %s, n2= %s%n", n1.toString(), n2.toString());
        try {
            num1 = (RealNumber) n1;
            num2 = (RealNumber) n2;
            //result = null;
        } catch (ClassCastException cce) {
            throw new ArithmeticException("Invalid Operation" + cce.getMessage());
        }
        if (op.equals("+")) {
            try {
                result = num1.add(num2);
            } catch (ArithmeticException ex) {
                throw new ArithmeticException("Invalid Operation" + ex.getMessage());
            }
        } else if (op.equals("-")) {
            try {
                result = num1.subtract(num2);
            } catch (ArithmeticException ex) {
                throw new ArithmeticException("Invalid Operation" + ex.getMessage());
            }
        } else if (op.equals("*")) {
            try {
                result = num1.multiply(num2);
            } catch (ArithmeticException ex) {
                throw new ArithmeticException("Invalid Operation" + ex.getMessage());
            }
        } else if (op.equals("/")) {
            try {
                result = num1.divide(num2);
            } catch (ArithmeticException ex) {
                throw new ArithmeticException("Invalid Operation" + ex.getMessage());
            }
        } else {
            throw new ArithmeticException("Invalid Operation");
        }
        return result;
    }//end doOp()

    //begin isLower()
    public boolean isLower(String op1, String op2) {
        List<String> hiOpsList = Arrays.asList(hiOps);
        if (hiOpsList.contains(op1) && hiOpsList.contains(op2)) {
            return false;
        } else if (!hiOpsList.contains(op1) && !hiOpsList.contains(op2)) {
            return false;
        } else if (hiOpsList.contains(op1) && !hiOpsList.contains(op2)) {
            return false;
        }
        return true;
    }//end isLower()
}//end Class RealNumber

